﻿using System;
using Microsoft.Web.Administration;

namespace Avivo.Tools
{
	public class IISHelper
	{
		/// <summary>
		/// Registers a 'http' and 'https' binding.
		/// </summary>
		/// <remarks>
		/// Bindings can be deleted in IIS7 - right click, select Edit Binding and delete.
		/// 
		/// Microsoft.Web.Administration namespace from assembly reference:
		/// %WinDir%\System32\InetSrv\Microsoft.Web.Administration.dll
		/// 
		/// Thanks to:
		/// http://forums.iis.net/t/1117559.aspx
		/// https://www.iis.net/ConfigReference/system.applicationHost/sites/site/bindings
		/// </remarks>
		/// <example>
		/// IISHelper.Register("my-domain.com", "www.my-domain.com");
		/// IISHelper.Register("my-domain.com", "admin.my-domain.com");
		/// </example>
		/// <param name="name"></param>
		/// <param name="domain"></param>
		public static void Register(string name, string domain)
		{
			if (string.IsNullOrEmpty(name))
			{
				throw new ArgumentException("'name' is missing!");
			}

			if (string.IsNullOrEmpty(domain))
			{
				throw new ArgumentException("'domain' is missing!");
			}

			using (ServerManager serverManager = new ServerManager())
			{
				//Get site element
				Configuration config = serverManager.GetApplicationHostConfiguration();
				ConfigurationSection sitesSection = config.GetSection("system.applicationHost/sites");
				ConfigurationElementCollection sitesCollection = sitesSection.GetCollection();
				ConfigurationElement siteElement = FindElement(sitesCollection, "site", "name", name);

				if (siteElement == null)
				{
					throw new Exception("Site not found! Name = " + name);
				}
				
				bool hasHttpBindingInfo = false;
				bool hasHttpsBindingInfo = false;
				string httpBindingInformation = @"*:80:" + domain;
				string httpsBindingInformation = @"*:443:" + domain;

				//Check if binding already exist
				var bindings = siteElement.GetCollection("bindings");
				foreach (var element in bindings)
				{
					bool isHttps = ((string)element.GetAttributeValue("protocol") == "https");
					if (isHttps)
					{
						element["bindingInformation"] = @"*:443:" + domain;
					}

					string bindingInformation = element.GetAttributeValue("bindingInformation") as string;
					if (bindingInformation == httpBindingInformation)
					{
						hasHttpBindingInfo = true;
					}
					else if (bindingInformation == httpsBindingInformation)
					{
						hasHttpsBindingInfo = true;
					}
				}

				//Add http binding if does not exist
				if (!hasHttpBindingInfo)
				{
					var bindingElement = bindings.CreateElement("binding");
					bindingElement["protocol"] = @"http";
					bindingElement["bindingInformation"] = @"*:80:" + domain;
					bindings.Add(bindingElement);
				}

				//Add https binding if does not exist
				if (!hasHttpsBindingInfo)
				{
					var bindingElement = bindings.CreateElement("binding");
					bindingElement["protocol"] = @"https";
					bindingElement["bindingInformation"] = @"*:443:" + domain;
					bindings.Add(bindingElement);
				}

				serverManager.CommitChanges();
			}
		}

		public static ConfigurationElement FindElement(ConfigurationElementCollection collection, string elementTagName, params string[] keyValues)
		{
			foreach (ConfigurationElement element in collection)
			{
				if (String.Equals(element.ElementTagName, elementTagName, StringComparison.OrdinalIgnoreCase))
				{
					bool matches = true;
					for (int i = 0; i < keyValues.Length; i += 2)
					{
						object o = element.GetAttributeValue(keyValues[i]);
						string value = null;
						if (o != null)
						{
							value = o.ToString();
						}
						if (!String.Equals(value, keyValues[i + 1], StringComparison.OrdinalIgnoreCase))
						{
							matches = false;
							break;
						}
					}
					if (matches)
					{
						return element;
					}
				}
			}
			return null;
		}
	}
}